﻿using ProtoBuf.Message;
using System;
using System.Collections;
using System.Collections.Generic;
using AutoChess;
using UnityEngine;
using Yunchang;

namespace AutoChess
{
    /// <summary>
    /// 缓存各个玩家的数据。 逻辑实体通过这些数据进行构建
    /// </summary>
    public class ACPlayerData
    {
        private long guid;
        private int shipId;      //船Id
        private int mapId;       //地图id
        private int sceneClientId; //场景资源表Id
        private int shipLevel;   //当前等级
        private int shipExp;     //船的经验
        private int gold;        //当前金币
        private int hp;          //当前显示的血量(等客户端展现完才同步真正的血量)
        private int hpCacheValue; //真正和服务器同步的血量
        private int rank;        //当前排名
        private string icon;     //英雄图标
        private string nickName; //玩家昵称
        private int fightLimit;  //上阵限制
        private int grade;       //玩家段位
        private bool lockState = false;

        private int interest;//利息
        private int seriesWin; //连胜次数
        private int seriesLose;//连败次数

        private bool isFirstInitShipData = true;
        #region 战斗结果信息
        //一个玩家匹配的信息
        public SCAutoChessMatchRes oneMatchRes;
        //一个玩家的匹配结果
        public SCAutoChessFightRes oneFightResult;
        #endregion

        private AutoChessLoadingProgress loadingProgress;//当前加载的进度

        public long GUID { get { return guid; } }
        public int ShipId { get { return shipId; }  set { shipId = value; } }
        public int MapId { get { return mapId; } }
        public int SceneClientId { get { return sceneClientId; } }
        public int ShipLevel { get { return shipLevel; } }
        public int ShipExp { get { return shipExp; } }
        public int Gold { get { return gold; } }
        public int HP { get { return hp; } }
        public bool IsDeath { get { return hp <= 0; } }
        public int Rank { get { return rank; } }
        public string Icon { get { return icon; } }
        public string NickName { get { return nickName; } }
        public int FightLimit { get { return fightLimit; } }
        public int Grade { get { return grade; } }
        public int Interest { get { return interest; } }
        public int SeriesWin { get { return seriesWin; } }
        public int SeriesLose { get { return seriesLose; } }
        public bool LockState { get { return lockState; }set{ lockState = value; } }

        public AutoChessLoadingProgress LoadingProgress { get { return loadingProgress; } set { loadingProgress = value; } }
        public FightPackage GetFightPackage()
        {
            var package = new FightPackage();
            package.fightShowTime = Table.DataModel.TableConfig.AutoChessFightDurationTime;
            package.playerGuid = guid;
            package.oneMatchRes = oneMatchRes;
            package.oneFightResult = oneFightResult;
            return package;
        }
        /// <summary>
        /// 当前数据是否和战场实体对应
        /// </summary>
        public bool IsCurrentEntityPlayer
        {
            get
            {
                if (AutoChessPlayerCtr.Ins.CurrentPlayer == null)
                {
                    //加载状态中 如果还没有创建玩家实体 .这个时候是不用创建消息进行逻辑刷新的
                    return false; /*GUID == StaticData.playerData.playerId*/;
                }
                return GUID == AutoChessPlayerCtr.Ins.CurrentPlayer.playerGuid;
            }
        }

        /// <summary>
        /// 是操作自己还是观战
        /// </summary>
        public bool IsSeeSelf { get { return guid == StaticData.playerData.playerId; } }

        //int 格子位置 ，HeroData 位置
        public Dictionary<int, HeroData> herosFight = new Dictionary<int, HeroData>();
        public Dictionary<int, HeroData> herosShop = new Dictionary<int, HeroData>();
        public Dictionary<int, HeroData> herosWait = new Dictionary<int, HeroData>();

        private Dictionary<int, int> heroFashionInfo = new Dictionary<int, int>();

        public void TestDelateOneHeroData()
        {
            int delateKey = 0;
            var ietor = herosWait.GetEnumerator();
            while (ietor.MoveNext())
            {
                delateKey = ietor.Current.Key;
                break;
            }
            herosWait.Remove(delateKey);
        }

        public int GetHeroFashionId(int heroId)
        {
            int fashionId = 0;
            heroFashionInfo.TryGetValue(heroId, out fashionId);
            return fashionId;
        }

        public void SelfDeath()
        {
            herosFight.Clear();
            herosShop.Clear();
            herosWait.Clear();
            heroFashionInfo.Clear();
        }
        public List<string> GetProfitDescNext()
        {
            List<string> result = new List<string>();
            var round = AutoChessManager.Ins.cacheData.RoundNum;
            result.Add( "x" + Table.Blo.AutoChessBlo.GetRoundBaseGold(round).ToString());//基础
            result.Add("x" + Interest.ToString());     //利息
            var roundTable = Table.Blo.AutoChessBlo.GetTableAutoChessRound(round + 1);
            result.Add( roundTable != null ? "x" + roundTable.winGold : "x0"); //胜利

            if (SeriesWin > 0)//连胜
            {
                var winSeries = Table.Blo.AutoChessBlo.GetSeriseStateTable(SeriesWin + 1);
                result.Add(winSeries != null ? "x" + winSeries.winGold : "x0");
            }
            else
            {
                result.Add("x 0");
            }

            if (SeriesLose > 0)//连败
            {
                var loseSeries = Table.Blo.AutoChessBlo.GetSeriseStateTable(SeriesLose + 1);
                result.Add(loseSeries != null ? "x" + loseSeries.loseGold : "x0");
            }
            else
            {
                result.Add("x0");
            }
            return result;
        }

        public List<HeroData> GetHeroList(GridType type,int maxNum = 100)
        {
            List<HeroData> hero = new List<HeroData>();
            if (type == GridType.FightGrid)
            {
                hero.AddRange(herosFight.Values);
            }
            else if (type == GridType.PreChooseGrid)
            {
                hero.AddRange(herosWait.Values);
            }
            else if (type == GridType.ShopGrid)
            {
                hero.AddRange(herosShop.Values);
            }
            hero.Sort((b, a) => {
                var aTable = Table.Blo.AutoChessBlo.GetChessTable(a.chessId);
                var bTable = Table.Blo.AutoChessBlo.GetChessTable(b.chessId);
                return aTable.sortScore.CompareTo(bTable.sortScore);
            });
            List<HeroData> heroResult = new List<HeroData>();

            for (int i = 0; i < hero.Count; i++)
            {
                if (i < maxNum)
                {
                    heroResult.Add(hero[i]);
                }
            }

            return heroResult;
        }

        #region 服务器推送的初始化数据
        public void UpdatePlayerInfo(AutoChessPlayerInfo msg)
        {
            this.mapId = msg.mapId;
            if (mapId == 0)
            {
                ExLog.LogError(string.Format("玩家{0}，地图数据异常：{1}！",msg.guid,msg.mapId));
            }
            this.sceneClientId = Table.Blo.AutoChessBlo.GetMapSceneClientIdByChessMapId(mapId);
            this.guid = msg.guid;
            this.icon = msg.icon;
            this.nickName = msg.nickname;
            this.grade = msg.grade;
            UpdateShipInfo(msg.shipInfo); //属性属性数据
            UpdateHeroInfo(msg.areaInfos);//创建 英雄数据

            heroFashionInfo.Clear();
            for (int i = 0; i < msg.fashionInfos.Count; i++)
            {
                heroFashionInfo[msg.fashionInfos[i].heroId] = msg.fashionInfos[i].fashionId;
            }
        }

        /// <summary>
        /// 服务器推送的初始化的信息
        /// </summary>
        /// <param name="heros"></param>
        private void UpdateHeroInfo(List<AutoChessAreaInfo> heros)
        {
            
            for (int i = 0; i < heros.Count; i++)
            {
                var info = heros[i];
                for (int n = 0; n < info.chessInfos.Count; n++)
                {
                    AddHeroData(info.type, info.chessInfos[n]);
                }
            }
        }

        /// <summary>
        /// 对格子添加操作(AutoChessChessInfo 添加新的)
        /// </summary>
        public HeroData AddHeroData(AutoChessAreaType type, AutoChessChessInfo msg)
        {
            HeroData data;
            var heroMap = GetHeroMap(type);
            var pos = UtilityHelper.GetClientPosFromServer(msg.pos) - 1;
            if (heroMap.ContainsKey(pos)) 
            {
                heroMap[pos].chessId = msg.chessId;
                data = heroMap[pos];
            }
            else
            {
                var heroData = new HeroData();
                heroData.chessId = msg.chessId;
                if (pos == -1)
                {
                    Debug.LogError("服务器数据错误，添加格子不能是 <0 的位置 ! <0约定是移除格子英雄");
                }

                heroData.svrId = msg.pos;
                heroData.gridIndex = pos;
                heroData.gridType = UtilityHelper.GetGridType(type);
                heroMap[pos] = heroData;
                data = heroData;
            }
            return data;
        }
        #endregion

        private Dictionary<int, HeroData> GetHeroMap(AutoChessAreaType type)
        {
            if (AutoChessAreaType.AUTO_CHESS_AREA_FIGHT == type)
            {
                return herosFight;
            }
            else if (AutoChessAreaType.AUTO_CHESS_AREA_WAITING == type)
            {
                return herosWait;
            }
            else
            {
                return herosShop;
            }
        }

        //将实际血量同步到显示血量
        public void ResetPlayerHPValue()
        {
            this.hp = hpCacheValue;
        }
        /// <summary>
        /// 更新属性信息
        /// </summary>
        /// <param name="shipInfo"></param>
        public void UpdateShipInfo(AutoChessShipInfo shipInfo)
        {
            this.shipId = shipInfo.shipId;
            this.shipLevel = shipInfo.shipLevel;
            this.shipExp = shipInfo.shipExp;
            this.gold = shipInfo.gold;
            this.hpCacheValue = shipInfo.hp;
            //血量的同步 放到首次播放完战斗结果 或者 如果没有播的话 放到切换到下个阶段去播放
            // 同步的时机 4个 ： 一个首次进游戏 , 一个出现炮弹， 或者结果展现(如果没有炮弹的话) ,两者可能都没有出现的话就是切到调整阶段进行处理

            if (isFirstInitShipData == true)
            {
                this.hp = hpCacheValue;
                EventManager.TriggerEvent(CommonEvent.ON_Refresh_Cache_HP);
                isFirstInitShipData = false;
            }

            this.rank = shipInfo.rank;
            this.fightLimit = shipInfo.fightChessNumLimit;
            this.interest = shipInfo.interest;

            if (seriesWin != shipInfo.seriesWin)
            {
                this.seriesWin = shipInfo.seriesWin;

                //需要判断是否已经进入游戏
                if (AutoChessManager.Ins.IsEnterSceneInit)
                {
                    AutoChessFieldViewCtr.Ins.ActionCtr.AddQueueAction(ActionQueueType.EndFight, () =>
                    {
                        EventManager.TriggerEvent(CommonEvent.ON_SHIP_MULITY_KILL, this);
                    }, 0.1f, 1);
                }
            }
            
            this.seriesLose = shipInfo.seriesLose;
            this.lockState = shipInfo.refreshLocked;
            //更新船只属性信息
            if (!IsCurrentEntityPlayer)
                return;
            //刷新当前的玩家信息
            EventManager.TriggerEvent(CommonEvent.UPDATE_PLAYER_INFO, guid);
        }

        #region 操作过程的更新 产生逻辑命令
        /// <summary>
        /// 解析服务器操作数据. 对格子的数据更新 都是操作的格子,这些格子,起始的格子一定要是要有英雄的
        /// </summary>
        /// <param name="parseInfo"></param>
        public void UpdateGridPos(AutoChessChessPosChangeInfo msg, AutoChessOpType opType)
        {
         
            //解析起始格子 开始格子 类型. 注意，from to 要判断当前 是交换还是 移动到一个新的空位置
            var fromType = UtilityHelper.GetAreaTypeFromPos(msg.srcPos);
            var fromPos = UtilityHelper.GetClientPosFromServer(msg.srcPos) - 1;
            var toType = UtilityHelper.GetAreaTypeFromPos(msg.tarPos);
            var toPos = UtilityHelper.GetClientPosFromServer(msg.tarPos) - 1;

            if (fromPos <= -1)
            {
                Debug.LogError("服务器数据错误,操作其实点数据不能为 <0");
                //出现了数据同步异常

                return;
            }
            HeroData from, to = null;
            var heroMapFrom = GetHeroMap(fromType);
            heroMapFrom.TryGetValue(fromPos, out from);

            if (from == null)//操作的一定有英雄的
            {
                Debug.LogError(string.Format("操作玩家 {0} 从 {1} 移除棋子 ,寻找本地英雄信息错误，From :{2},to:{3},  本地数据缓存数据和服务器数据不一致!",
                    guid, fromType.ToString(), msg.srcPos, msg.tarPos));
               // return;
            }

            if (toPos <= -1)//移除格子
            {
                heroMapFrom.Remove(fromPos);

                CreateRemoveOneGridHeroMsg((GridType)fromType, from.chessId, fromPos, opType); //移除棋子
                return;
            }
            var heroMapTo = GetHeroMap(toType);
            heroMapTo.TryGetValue(toPos, out to);

            if (to != null) //from 和 to 交换位置
            {
                heroMapFrom.Remove(fromPos);
                heroMapTo.Remove(toPos);

                //from 先到到 to的区域
                from.gridType = UtilityHelper.GetGridType(toType);
                from.gridIndex = toPos;
                heroMapTo.Add(toPos, from);
                
                //to  到 from
                to.gridType = UtilityHelper.GetGridType(fromType);
                to.gridIndex = fromPos;
                heroMapFrom.Add(fromPos, to);

                CreateSwitchGridHeroMsg((GridType)fromType, fromPos, (GridType)toType, toPos);
            }
            else  //from 移到 to
            {
                heroMapFrom.Remove(fromPos);

                //跑到新的格子
                from.gridType = UtilityHelper.GetGridType(toType);
                from.gridIndex = toPos;

                heroMapTo.Add(toPos, from);
                CreateSwitchGridHeroMsg((GridType)fromType, fromPos, (GridType)toType, toPos);
            }
        }
        /// <summary>
        /// 和操作更新的时候一起调用这个添加的
        /// </summary>
        /// <param name="msg"></param>
        public void OnOpreateAddHeroData(AutoChessChessInfo msg, AutoChessOpType type)
        {
            var areaType = UtilityHelper.GetAreaTypeFromPos(msg.pos);
            var heroData = AddHeroData(areaType, msg);

            CreateAddOneGridHeroMsg(heroData, type);
        }
        #endregion

        #region 构建指令
        /// <summary>
        /// 交换或移动英雄
        /// </summary>
        public void CreateSwitchGridHeroMsg(GridType fromGridType, int fromIndex, GridType toGridType, int toIndex)
        {
            if (!IsCurrentEntityPlayer)
                return;

            var fromUnit = AutoChessMapMgr.Ins.GetGridPos(fromGridType, fromIndex);
            var toUnit = AutoChessMapMgr.Ins.GetGridPos(toGridType, toIndex);

            EventManager.TriggerEvent<OpretionMsg>(CommonEvent.PUSH_GAMEFIELD_MSG, GridOpretionMsg.NewSwitchGridHeroMsg(fromUnit, toUnit));
        }

        /// <summary>
        /// 移除一个格子英雄
        /// </summary>
        public void CreateRemoveOneGridHeroMsg(GridType fromGridType, int chessId ,int fromIndex, AutoChessOpType opType)
        {
            if (!IsCurrentEntityPlayer)
                return;

            //var fromUnit = AutoChessMapMgr.Ins.GetGridPos(fromGridType, fromIndex); //不能直接寻找，应为逻辑运算走的队列， 直接取逻辑体 不一定已经是正确的 逻辑
            var package = new HeroRemoveMsgPackage() { chessId = chessId , gridType = fromGridType,gridIndex = fromIndex};
            EventManager.TriggerEvent<OpretionMsg>(CommonEvent.PUSH_GAMEFIELD_MSG, HeroOpretionMsg.NewHeroDisappearMsg(package , opType));

            ExLog.LogV(string.Format("指令 移除一个棋子 {1} 位置 {2}</color>", guid, chessId, fromIndex));
        }

        /// <summary>
        /// 添加格子
        /// </summary>
        public void CreateAddOneGridHeroMsg(HeroData data, AutoChessOpType opType)
        {
            //EventManager.TriggerEvent(CommonEvent.ON_SHIP_STAR_UP, HeroOpretionMsg.NewHeroAppearMsg(data, opType), NickName);

            if (!IsCurrentEntityPlayer)
                return;

            //var fromUnit = AutoChessMapMgr.Ins.GetGridPos(data.gridType, data.gridIndex);
            //if (fromUnit.heroUnit != null) //如果当前格子上有英雄 就直接替换
            //{
            //    EventManager.TriggerEvent<OpretionMsg>(CommonEvent.PUSH_GAMEFIELD_MSG, HeroOpretionMsg.NewHeroDisappearMsg(fromUnit.heroUnit, opType));
            //    ExLog.LogV(string.Format("替换一个棋子 {1} 位置 {2}</color>", guid, fromUnit.heroUnit.chessId, data.gridIndex));
            //}
            EventManager.TriggerEvent<OpretionMsg>(CommonEvent.PUSH_GAMEFIELD_MSG, HeroOpretionMsg.NewHeroAppearMsg(data, opType));

            ExLog.LogV(string.Format("添加一个棋子 {1} 位置 {2}</color>", guid,data.chessId, data.gridIndex));
        }
        #endregion
    }

    /// <summary>
    /// 棋子信息
    /// </summary>
    public class HeroData
    {
        public long ownerPlayerId = 0;
        /// <summary>服务器唯一ID</summary>
        public int svrId;
        /// <summary>棋子在的格子类型 </summary>
        public GridType gridType;
        /// <summary>棋子id </summary>
        public int chessId;
        /// <summary>棋子在的格子ID </summary>
        public int gridIndex;

        public BattleSide GetBattleSide()
        {
            if (gridType == GridType.EnemyGrid)
            {
                return BattleSide.Right;
            }
            else if (gridType == GridType.FightGrid)
            {
                return BattleSide.Left;
            }
            else
            {
                return BattleSide.None;
            }
        }

        public override string ToString()
        {
            return string.Format("Grid:{0}, chessId:{1} , gridIndex:{2}",gridType.ToString(),chessId,gridIndex);
        }
    }

}
